package generate

import (
	"bytes"
	"go/parser"
	"go/printer"
	"go/token"
	"html/template"
	"io/ioutil"
	"log"
	"strings"
)

type Generator interface {
	GetName() string
	GetModel() interface{}
	Generate(fset *FileSet)
}

func PrintFile(fset *FileSet, g Generator) error {
	content, err := Generate(fset, g)
	if err != nil {
		return err
	}
	if err := Format(content); err != nil {
		log.Printf("Format code failed, code:\n%s", content)
		return err
	}
	filename := strings.TrimSuffix(fset.File, ".go") + "_code.go"
	return ioutil.WriteFile(filename, content.Bytes(), 0644)
}

func Format(buffer *bytes.Buffer) error {
	fset := token.NewFileSet()
	sfile, err := parser.ParseFile(fset, "", buffer, parser.ParseComments)
	if err != nil {
		return err
	}

	buffer.Reset()
	err = (&printer.Config{Mode: printer.TabIndent, Tabwidth: 8}).Fprint(buffer, fset, sfile)
	if err != nil {
		return err
	}
	return nil
}

func Generate(fset *FileSet, g Generator) (*bytes.Buffer, error) {
	// fill template and value
	g.Generate(fset)

	tpl, err := template.New("tpl").Parse(g.GetName())
	if err != nil {
		return nil, err
	}

	var buffer bytes.Buffer
	if err := tpl.Execute(&buffer, g.GetModel()); err != nil {
		return nil, err
	}

	return &buffer, nil
}
